package baseChips

func Not(a bool) bool {
	return !a
}

func Nand(a bool, b bool) bool {
	return Not(a) || Not(b)
}

func Mux(a bool, b bool, set bool) bool {
	return Or(And(b, set), And(a, Not(set)))
}

func Or(a bool, b bool) bool {
	return Nand(Nand(a, a), Nand(b, b))
}

func And(a bool, b bool) bool {
	return Nand(Nand(a, b), Nand(b, a))
}

func Nor(a bool, b bool) bool {
	return Not(Or(a, b))
}

func Xor(a bool, b bool) bool {
	return And(Nand(a, b), Or(a, b))
}

func Mux16(a [16]bool, b [16]bool, sel bool) [16]bool {
	rs := [16]bool{}
	for i := 0; i < len(rs); i++ {
		rs[i] = Mux(a[i], b[i], sel)
	}
	return rs
}

func DMux(in bool, sel bool) (bool, bool) {
	return And(in, Not(sel)), And(in, sel)
}

func DMux4Way(in bool, sel [2]bool) (a bool, b bool, c bool, d bool) {
	o1, o2 := DMux(in, sel[1])
	a, b = DMux(o1, sel[0])
	c, d = DMux(o2, sel[0])
	return a, b, c, d
}

func DMux8Way(in bool, sel [3]bool) (a bool, b bool, c bool, d bool, e bool, f bool, g bool, h bool) {
	o1, o2, o3, o4 := DMux4Way(in, [2]bool{sel[1], sel[2]})
	a, b = DMux(o1, sel[0])
	c, d = DMux(o2, sel[0])
	e, f = DMux(o3, sel[0])
	g, h = DMux(o4, sel[0])
	return a, b, c, d, e, f, g, h
}

func Mux4Way16(a [16]bool, b [16]bool, c [16]bool, d [16]bool, sel [2]bool) (out [16]bool) {
	o1 := Mux16(a, b, sel[0])
	o2 := Mux16(c, d, sel[0])
	return Mux16(o1, o2, sel[1])
}

func Mux8Way16(a [16]bool, b [16]bool, c [16]bool, d [16]bool, e [16]bool, f [16]bool, g [16]bool, h [16]bool, sel [3]bool) (out [16]bool) {
	o1 := Mux4Way16(a, b, c, d, [2]bool{sel[0], sel[1]})
	o2 := Mux4Way16(e, f, g, h, [2]bool{sel[0], sel[1]})

	return Mux16(o1, o2, sel[2])
}

func Not16(a [16]bool) (out [16]bool) {
	for i := 0; i < len(a); i++ {
		out[i] = Not(a[i])
	}
	return out
}
